/*
Christopher Raffaele
02/18/2010
CSC280
Assignement 2 Towers of Hanoi

HanoiGame.cpp.h
*/

#include"HanoiGame.h"

using namespace std;

//CTOR
HanoiGame::HanoiGame(unsigned int numDisks){
	if(numDisks < 1)
		throw new exception("Number of disks must be greater than 0");

	//set moves to zero
	moves = 0;

	totalDisks = numDisks;
	finished = false;

	//create some towers
	towerA = new Tower(totalDisks);
	towerB = new Tower(0);
	towerC = new Tower(0);

	tempmsg = "";
}

//DTOR
HanoiGame::~HanoiGame(){
	//cleanup tower memory
	delete towerA;
	towerA = NULL;

	delete towerB;
	towerB = NULL;

	delete towerC;
	towerC = NULL;
}

//Solve
void HanoiGame::Solve(unsigned int numDisks, char fromTower, char toTower, char openTower){
	//hanoi solving recursive algorithm 
	if(numDisks > 0){
		Solve(numDisks - 1, fromTower, openTower, toTower);
		Swap(fromTower, toTower);

		//to ensure that the move list doesn't get too large
		if(tempmsg.length() / 26 > 300){
			tempmsg.erase(0, tempmsg.find_first_of("\n") + 1);
		}

		tempmsg += lastMove;
		tempmsg += "\n";

		Solve(numDisks - 1, openTower, toTower, fromTower);
	}
}

//Swap
void HanoiGame::Swap(const char fromTower, const char toTower){
	//reset last move description
	lastMove = "";

	//do nothing if the from and to towers are the same
	if(fromTower == toTower)
		return;

	//get the correct towers corresponding to the letters entered
	Tower* fTower;

	switch(fromTower){
		case 'a':
			fTower = towerA; 
			break;
		case 'b':
			fTower = towerB;
			break;
		case 'c':
			fTower = towerC;
			break;
	}

	Tower* tTower;

	switch(toTower){
		case 'a':
			tTower = towerA;
			break;
		case 'b':
			tTower = towerB;
			break;
		case 'c':
			tTower = towerC;
			break;
	}

	//make sure the from tower isnt empty
	if(fTower->Size() > 0){
		//get the data from the from tower
		int temp = fTower->Top();

		//swap if the to tower's top is less than the from tower
		if(tTower->Size() < 1 || temp < tTower->Top()){
			fTower->Pop();
			tTower->Push(temp);

			//increment moves
			++moves;

			//build move descriptor
			lastMove = "Move #";

			char* tempstr = new char[20];
			_itoa_s(moves, tempstr, 20, 10);
			lastMove += tempstr;

			lastMove += ": ";

			_itoa_s(temp, tempstr, 20, 10);
			lastMove += tempstr;
			delete tempstr;

			lastMove += " from tower ";
			lastMove += fromTower;
			lastMove += " to ";
			lastMove += toTower;
		}
	}

	//null pointers
	fTower = NULL;
	tTower = NULL;

	//check for completion
	if(towerC->Size() == totalDisks)
		finished = true;
}

//operator <<
ostream& operator<<(ostream& os, const HanoiGame& aHanoiGame){
	os << "Towers of Hanoi - " << aHanoiGame.totalDisks << " Disks " << aHanoiGame.moves << " moves\nTower - Top ... Bottom\n\n";

	//print out the total moves if the game as been auto solved
	if(aHanoiGame.tempmsg.length() > 0){
		os << aHanoiGame.tempmsg.c_str() << "\n\n";
	//print out the alst move if the game is being solved manually
	}else if(aHanoiGame.lastMove.length() > 0){
		os << aHanoiGame.lastMove.c_str() << "\n\n";
	}

	//print out contents of the towers
	os << "a - " << *aHanoiGame.towerA << "\n\n";
	os << "b - " << *aHanoiGame.towerB << "\n\n";
	os << "c - " << *aHanoiGame.towerC << "\n\n";

	return os;
}